package com.crane.common.framework.shiro;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.TimeUnit;


public class ShiroRedisSessionDAO extends AbstractSessionDAO {

    private int redisSessionTimeout = 60 * 60 * 2;

    public static final String DEFAULT_SESSION_KEY_PREFIX = "shiro:session:";

    private String keyPrefix;

    private RedisTemplate<String, Session> redisTemplate;

    //更改默认的序列化方式，session用jdk序列化方式，shiro session属性无类型，反序列化时候map转成相应的类会报错
    //JdkRedisSerializer<Serializable> collectionSerializer=JdkRedisSerializer.getInstance();
    //redisTemplate.setValueSerializer(collectionSerializer);

    @Override
    public void update(Session session) throws UnknownSessionException {
        storeSession(session.getId(), session);
    }

    @Override
    public void delete(Session session) {
        if (session == null) {
            throw new NullPointerException("session argument cannot be null.");
        }
        Serializable id = session.getId();
        if (id != null) {
            redisTemplate.delete((getSessionId(id)));
        }
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Set<String> keys = redisTemplate.keys(getKeyPrefix() + "*");
        Collection<Session> sessions = redisTemplate.opsForValue().multiGet(keys);
        if (CollectionUtils.isEmpty(sessions)) {
            return Collections.emptySet();
        } else {
            return sessions;
        }
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = generateSessionId(session);
        assignSessionId(session, sessionId);
        storeSession(sessionId, session);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        Session session = null;
        if (redisTemplate.hasKey(getSessionId(sessionId))) {
            session = redisTemplate.opsForValue().get(getSessionId(sessionId));
        }
        return session;
    }

    protected Session storeSession(Serializable id, Session session) {
        if (id == null) {
            throw new NullPointerException("id argument cannot be null.");
        }
        redisTemplate.opsForValue().set(getSessionId(id), session, redisSessionTimeout, TimeUnit.SECONDS);
        return session;
    }

    private String getSessionId(Serializable id) {
        if (id == null) {
            throw new NullPointerException("id argument cannot be null.");
        }
        return this.getKeyPrefix() + id.toString();
    }

    public int getRedisSessionTimeout() {
        return redisSessionTimeout;
    }

    public void setRedisSessionTimeout(int redisSessionTimeout) {
        this.redisSessionTimeout = redisSessionTimeout;
    }

    public String getKeyPrefix() {
        if (StringUtils.hasLength(keyPrefix)) {
            return DEFAULT_SESSION_KEY_PREFIX + keyPrefix + ":";
        }
        return DEFAULT_SESSION_KEY_PREFIX;
    }

    public void setKeyPrefix(String keyPrefix) {
        this.keyPrefix = keyPrefix;
    }

    public RedisTemplate<String, Session> getRedisTemplate() {
        return redisTemplate;
    }

    //	@Autowired
//	@Qualifier("shiroRedisSessionRedisTemplate")
    public void setRedisTemplate(RedisTemplate<String, Session> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


}
